package com.zhl.common.utils;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import com.zhl.common.exception.BusinessException;
import com.zhl.common.properties.AliOssProperties;
import com.zhl.common.util.StrUtils;
import lombok.extern.slf4j.Slf4j;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @description 阿里云oss操作
 * @Author: z156940l@outlook.com
 * @className OSSUtils
 * @Date: 2024/7/21 13:14
 */
@Slf4j
public class OSSUtils {

    private final AliOssProperties aliOssCos;

    public OSSUtils(AliOssProperties aliOssCos){
        this.aliOssCos = aliOssCos;
    }

    //OSS对象
    private OSSClient ossClient;


    private void initOss() {
        try {
            log.info("Oss client init start");
            ossClient = new OSSClient(aliOssCos.getEndpoint(), aliOssCos.getAccessKeyId(), aliOssCos.getAccessKeySecret());
            //判断bucketName是否存在，不存在则创建
            if (!ossClient.doesBucketExist(aliOssCos.getBucketName())) {
                ossClient.createBucket(aliOssCos.getBucketName());
                log.info("oss bucket created success!");
            }
        } catch (ClientException e) {
            log.error(e.toString());
        }
    }

    /**
     * Description: 关闭ossClient对象
     *
     * @Date:2018/7/17
     */
    private void closeOssClient() {
        try {
            ossClient.shutdown();
        } catch (ClientException e) {
            log.error(e.toString());
        }
    }

    /**
     * Description: 字节流上传文件
     *
     * @Date:2018/7/17
     */
    public void upload(String key, Object o) {
        try {
            initOss();
            InputStream is = new ByteArrayInputStream(o.toString().getBytes());
            ossClient.putObject(aliOssCos.getBucketName(), key, is);
            closeOssClient();
        } catch (Exception e) {
            log.error(e.toString());
        }
    }

    /**
     * Description: 下载对象
     *
     * @Date:2018/7/17
     */
    public Object downLoad(String key) {
        StringBuilder objectContent = null;
        try {
            initOss();
            OSSObject ossObject = ossClient.getObject(aliOssCos.getBucketName(), key);
            InputStream inputStream = ossObject.getObjectContent();
            objectContent = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            while (true) {
                String line = reader.readLine();
                if (line == null) {
                    break;
                }
                objectContent.append(line);
            }
            inputStream.close();
            closeOssClient();
            return objectContent;
        } catch (Exception e) {
            log.error(e.toString());
        }
        return objectContent;
    }

    /**
     * 根据文件key和bucketName下载文件
     *
     * @param key    文件名
     * @param bkName bucketName名
     * @return
     */
    public Object downLoadBucketName(String key, String bkName) {
        StringBuilder objectContent = null;
        InputStream inputStream = null;
        BufferedReader reader = null;
        OSSClient ossClient = null;
        try {
            ossClient = new OSSClient(aliOssCos.getEndpoint(), aliOssCos.getAccessKeyId(), aliOssCos.getAccessKeySecret());
            OSSObject ossObject = ossClient.getObject(bkName, key);
            inputStream = ossObject.getObjectContent();
            objectContent = new StringBuilder();
            reader = new BufferedReader(new InputStreamReader(inputStream));
            while (true) {
                String line = reader.readLine();
                if (line == null) {
                    break;
                }
                objectContent.append(line);
            }
            return objectContent;
        } catch (Exception e) {
            log.error("从OSS服务器下载文件出现异常!", e);
            throw new BusinessException("从OSS服务器下载文件出现异常!");
        } finally {
            if (ossClient != null) {
                try {
                    ossClient.shutdown();
                } catch (Exception e) {
                    log.error("关闭ossClient异常", e);
                }
            }
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (Exception e) {
                log.error("关闭inputStream异常", e);
            }
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (Exception e) {
                log.error("关闭reader异常", e);
            }
        }
    }


    public String uploadObject2OSS(File file) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String folder = format.format(new Date());
        String resultStr = null;
        String fileName = null;
        try {
            initOss();
            //以输入流的形式上传文件
            InputStream is = new FileInputStream(file);
            //文件名
            fileName = UUID.randomUUID().toString().replace("-", "") + file.getName().substring(file.getName().indexOf("."), file.getName().length());
            //文件大小
            Long fileSize = file.length();
            //创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
            //上传的文件的长度
            metadata.setContentLength(is.available());
            //指定该Object被下载时的网页的缓存行为
            metadata.setCacheControl("no-cache");
            //指定该Object下设置Header
            metadata.setHeader("Pragma", "no-cache");
            //指定该Object被下载时的内容编码格式
            metadata.setContentEncoding("utf-8");
            //文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
            //如果没有扩展名则填默认值application/octet-stream
            metadata.setContentType(getContentType(fileName));
            //指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
            metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
            //上传文件   (上传文件流的形式)
            PutObjectResult putResult = ossClient.putObject(aliOssCos.getBucketName(), folder + "/" + fileName, is, metadata);
            //解析结果
            resultStr = putResult.getETag();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
        }
        return folder + "/" + fileName;
    }

    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     *
     * @param fileName 文件名
     * @return 文件的contentType
     */
    public static String getContentType(String fileName) {
        //文件的后缀名
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
        if (".bmp".equalsIgnoreCase(fileExtension)) {
            return "image/bmp";
        }
        if (".gif".equalsIgnoreCase(fileExtension)) {
            return "image/gif";
        }
        if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension) || ".png".equalsIgnoreCase(fileExtension)) {
            return "image/jpeg";
        }
        if (".html".equalsIgnoreCase(fileExtension)) {
            return "text/html";
        }
        if (".txt".equalsIgnoreCase(fileExtension)) {
            return "text/plain";
        }
        if (".vsd".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.visio";
        }
        if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.ms-powerpoint";
        }
        if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
            return "application/msword";
        }
        if (".xml".equalsIgnoreCase(fileExtension)) {
            return "text/xml";
        }
        //默认返回类型
        return "image/jpeg";
    }


    /**
     * 获取图片URL
     *
     * @param key
     * @return
     */
    public String queryImgUrl(String key) {
        String path = null;
        //设置过期时间
        Date expiration = new Date(System.currentTimeMillis() + 100 * 365 * 24 * 3600 * 1000);
        try {
            initOss();
            URL url = ossClient.generatePresignedUrl(aliOssCos.getBucketName(), key, expiration);
            path = url.toString();
            ossClient.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                closeOssClient();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return path;
    }


    /**
     * @return 服务器上文件key
     */
    public String uploadInputStream(InputStream inputStream, String fileName, Long fileSize) throws BusinessException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String folder = format.format(new Date());
        String resultStr = null;
        try {
            initOss();
            //以输入流的形式上传文件
            InputStream is = inputStream;
            //文件名
            fileName = UUID.randomUUID().toString() + fileName.substring(fileName.lastIndexOf("."), fileName.length());
            //创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
            //上传的文件的长度
            metadata.setContentLength(is.available());
            //指定该Object被下载时的网页的缓存行为
            metadata.setCacheControl("no-cache");
            //指定该Object下设置Header
            metadata.setHeader("Pragma", "no-cache");
            //指定该Object被下载时的内容编码格式
            metadata.setContentEncoding("utf-8");
            //文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
            //如果没有扩展名则填默认值application/octet-stream
            metadata.setContentType(getContentType(fileName));
            //指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
            metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
            //上传文件   (上传文件流的形式)
            PutObjectResult putResult = ossClient.putObject(aliOssCos.getBucketName(), folder + "/" + fileName, is, metadata);
            //解析结果
            resultStr = putResult.getETag();
            ossClient.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("上传阿里云OSS服务器异常.{}", e.getMessage());
            throw new BusinessException("上传阿里云OSS服务器异常.");
        }
        return folder + "/" + fileName;
    }

    /**
     * 获取文件InputStream
     *
     * @param ossFileKey
     * @return
     */
    public InputStream downLoadImg(String ossFileKey) {
        InputStream inputStream = null;
        try {
            initOss();
            OSSObject ossObject = ossClient.getObject(aliOssCos.getBucketName(), ossFileKey);
            inputStream = ossObject.getObjectContent();
        } catch (Exception e) {
            log.error(e.toString());
        }
        return inputStream;
    }

    /**
     * oss buckname拷贝
     *
     * @param sourceName 源buckname
     * @param targetName 目标buckname
     * @param fileNames  文件名称
     */
    public void bucketNameCopy(String sourceName, String targetName, List<String> fileNames) {
        initOss();
        for (String fileName : fileNames) {
            CopyObjectResult result = ossClient.copyObject(sourceName, fileName, targetName, fileName);
            log.info(fileName + "迁移成功");
        }
        ossClient.shutdown();

    }

    /**
     * @return List<String>  fileName集合
     * @MethodName: getFileName
     * @Description: 根据url获取fileNames集合
     */
    public List<String> getAllFileNamesFromBucket(String bucketName) {
        OSSClient ossClient = new OSSClient(aliOssCos.getEndpoint(), aliOssCos.getAccessKeyId(), aliOssCos.getAccessKeySecret());
        List<String> fileNames = new ArrayList<>();
        // 构造ListObjectsRequest请求
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
        recursionGetFileNames(ossClient, fileNames, listObjectsRequest, null);
        ossClient.shutdown();
        return fileNames;
    }

    private void recursionGetFileNames(OSSClient ossClient, List<String> fileNames, ListObjectsRequest listObjectsRequest, String nextMarker) {
        if (StrUtils.isBlank(nextMarker)) {
            listObjectsRequest.setMarker(nextMarker);
        }
        ObjectListing listing = ossClient.listObjects(listObjectsRequest);
        // 获取目录下面所有文件
        for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) {
            fileNames.add(objectSummary.getKey());
        }
        nextMarker = listing.getNextMarker();
        if (StrUtils.isNotBlank(nextMarker)) {
            recursionGetFileNames(ossClient, fileNames, listObjectsRequest, nextMarker);
        }
    }


    /**
     * 图片转转换
     *
     * @param image
     * @return
     */
    public static BufferedImage coverToBufferedImage(Image image) {
        if (image instanceof BufferedImage) {
            return (BufferedImage) image;
        }
        // This code ensures that all the pixels in the image are loaded
        image = new ImageIcon(image).getImage();
        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment
                .getLocalGraphicsEnvironment();
        try {
            int transparency = Transparency.OPAQUE;
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(image.getWidth(null),
                    image.getHeight(null), transparency);
        } catch (HeadlessException e) {
            // The system does not have a screen
        }
        if (bimage == null) {
            // Create a buffered image using the default color model
            int type = BufferedImage.TYPE_INT_RGB;
            bimage = new BufferedImage(image.getWidth(null),
                    image.getHeight(null), type);
        }
        // Copy image to buffered image
        Graphics g = bimage.createGraphics();
        // Paint the image onto the buffered image
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return bimage;
    }
}
